package ws

import (
	"context"
	"gitee.com/xcy871622040/gameframe/logger"
	"github.com/panjf2000/gnet/v2"
	"github.com/robfig/cron/v3"
	"github.com/xcy8712622040/gnetws/net-protocol/websocket"
	"github.com/xcy8712622040/gnetws/net-protocol/websocket/dstservice"
	"github.com/xcy8712622040/gnetws/serverhandler"
)

type GnetEventHandlePlugin struct{}

// OnOpen tcp链接建立成功之后 注册 http升websocket
func (g *GnetEventHandlePlugin) OnOpen(ctx *serverhandler.Context) (out []byte, action gnet.Action) {
	ctx.WithHandler(new(websocket.WithWebSocketUpgradeHandle))
	return out, action
}

type WebSocketHandlePlugin struct {
	ServerFactory func() *dstservice.Service
}

// OnUpgrade ws升级成功之后注册ws帧处理
func (w *WebSocketHandlePlugin) OnUpgrade(ctx *serverhandler.Context, _ *websocket.Conn, path string) error {
	ctx.WithHandler(&websocket.WithWebSocketFrameHandler{
		FrameHandler: w.ServerFactory().WithUrl2Proc(path),
	})
	return nil
}

type withopt func(option *GateServer)

func WithGnetEventHandlePlugin(plugin serverhandler.EventPlugin) withopt {
	return func(server *GateServer) {
		server.Handler.Plugins().Add(plugin)
	}
}

func WithWebsocketHandlePlugin(plugin websocket.WsPlugin) withopt {
	return func(server *GateServer) {
		websocket.WsPlugins().Add(plugin)
	}
}

func WithWebsocketHandleService(service *dstservice.Service) withopt {
	return func(option *GateServer) {
		option.service = service
	}
}

type GateServer struct {
	*serverhandler.Handler

	options []gnet.Option
	service *dstservice.Service
}

// Start GatewaySetvet Start 方法
func (g *GateServer) Start(ctx context.Context, addr string) error {
	return g.Handler.Start(ctx, addr, g.options...)
}

// WithGnetEventHandleOption 设置gnet的启动选项 具体参考 gnet options 说明
func (g *GateServer) WithGnetEventHandleOption(opts ...gnet.Option) {
	g.options = append(g.options, opts...)
}

func NewServer(opts ...withopt) (s *GateServer) {
	s = new(GateServer)
	s.service = dstservice.GlobalService
	s.Handler = serverhandler.NewHandler(
		serverhandler.WithCron(cron.New(
			cron.WithSeconds(),
		)),
		serverhandler.WithLogger(
			logger.GameLog.WithField("kind", "gateway"),
		),
	)

	s.Handler.Plugins().Add(&GnetEventHandlePlugin{})
	websocket.WsPlugins().Add(&WebSocketHandlePlugin{ServerFactory: func() *dstservice.Service {
		return s.service
	}})

	for i := range opts {
		opts[i](s)
	}
	return
}
